#include "config_dao.h"
#include <lxmysql/LXMysql.h>
#include <xplatform/XTools.h>
#include <xplatform/protobuf/xmsg_com.pb.h>
#include <sstream>
#include <cstring>
#include <tool/Base64.h>
// #define CONFIG_FILE "config.xml"
#define CONFIG_TABLE "xms_service_config"

static std::mutex my_mutex;

bool ConfigDao::Init(const char *ip, const char *user, const char *pwd, const char *dbname, unsigned short port)
{
    std::unique_lock<std::mutex> lock(my_mutex);
    if(!m_mysql)m_mysql=new LX::LXMysql;
    bool ret = m_mysql->Init();
    if(!ret){
        XCOM_LOG_DEBUG("mysql init error");
        return false;
    }
    // 自动重连
    m_mysql->SetReconnect(true);
    // 连接超时
    m_mysql->SetConnectTimeout(5);
    if(!m_mysql->Connect(ip,user,pwd,dbname,port)){
        XCOM_LOG_DEBUG("mysql Connect error:"<<m_mysql->GetErrorStr());
        return false;
    }
    return true;
}

bool ConfigDao::Install()
{
    if(!m_mysql){
        return false;
    }
    auto sql = R"(CREATE TABLE IF NOT EXISTS `xms_service_config`(
  `id` int NOT NULL AUTO_INCREMENT,
  `service_name` varchar(100) NOT NULL,
  `service_port` int NOT NULL,
  `service_ip` varchar(16) NOT NULL,
  `private_pb` varchar(4096) NOT NULL,
  `proto` varchar(4096) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci)";
    if(m_mysql->Query(sql)){
        XCOM_LOG_DEBUG("mysql create table xms_service_config success");
        return true;
    }
    return false;
}

bool ConfigDao::SaveConfig(xmsg::XConfig *config)
{
    XCOM_LOG_DEBUG("ConfigDao::SaveConfig");
    std::unique_lock<std::mutex> lock(my_mutex);
    if(!m_mysql){
        XCOM_LOG_DEBUG("mysql is null");
        return false;
    }
    if(!config||config->service_ip().empty()){
        XCOM_LOG_DEBUG("config is null||config->service_ip().empty()");
        return false;
    }
    auto table_name = CONFIG_TABLE;
    LX::XDATA data;
    data["service_name"] = config->service_name().c_str();
    auto service_port = config->service_port();
    data["service_port"] = &service_port;
    data["service_ip"] = config->service_ip().c_str();
    std::string pb = config->SerializeAsString();
    std::string pb_=base64_encode(pb);
    config->set_private_pb(pb_);
    data["private_pb"].data= pb_.c_str();
    data["private_pb"].size= pb_.size();
    data["private_pb"].type = LX::LX_TYPE_STRING;
    data["proto"].data= config->proto().c_str();
    data["proto"].size= config->proto().size();
    std::stringstream ss;
    ss<<"select id from "<<table_name<<" where service_ip='"<<config->service_ip()<<"' "
    <<"and service_port="<<config->service_port();
    auto rows = m_mysql->GetResult(ss.str());
    if(rows.size()>0){
        auto s = std::string("where id=")+rows[0][0].data;
        return m_mysql->UpdateBinary(data,table_name,s.c_str());
    }
    return m_mysql->InsertBinary(data,std::string("xms_service_config"));
}

xmsg::XConfig ConfigDao::LoadConfig(const char* ip,int port)
{
    xmsg::XConfig config;
    XCOM_LOG_DEBUG("ConfigDao::LoadConfig");
    std::unique_lock<std::mutex> lock(my_mutex);
    if(!m_mysql){
        XCOM_LOG_DEBUG("m_mysql not init");
        return config;
    }
    if(!ip||port<=0||port>65535||strlen(ip)==0){
        XCOM_LOG_DEBUG("ip or port error");
        return config;
    }
    std::string table_name=CONFIG_TABLE;
    std::stringstream sql;
    sql<<"select private_pb from "<<table_name<<" where service_ip='"<<ip<<"' and service_port="<<port;
    auto rows = m_mysql->GetResult(sql.str());
    if(rows.size()<=0){
        return config;
    }
    std::string pb_=base64_decode(std::string(rows[0][0].data,rows[0][0].size));
    bool ret = config.MergeFromString(pb_);
    if(!ret) return xmsg::XConfig();
    return config;
}

xmsg::XConfigList ConfigDao::LoadAllConfig(int page, int page_count)
{
    XCOM_LOG_DEBUG("ConfigDao::LoadAllConfig");
    std::unique_lock<std::mutex> lock(my_mutex);
    if(!m_mysql){
        XCOM_LOG_DEBUG("m_mysql not init");
        return xmsg::XConfigList();
    }
    if(page<0||page_count<=0){
        XCOM_LOG_DEBUG("page or page_count error");
        return xmsg::XConfigList();
    }
    auto table_name = CONFIG_TABLE;
    std::string sql = std::string("select service_name,service_port,service_ip from ") + table_name + " limit " + std::to_string(page_count) + " offset " + std::to_string((page-1) * page_count);
    if(!m_mysql->Exec(sql)){
        XCOM_LOG_DEBUG("Exec(sql) error");
        return xmsg::XConfigList();
    }
    xmsg::XConfigList configList;
    while(m_mysql->Next()){
        xmsg::XConfig *config=configList.add_config();
        config->set_service_name(m_mysql->Value(0));
        config->set_service_port(atoi(m_mysql->Value(1).c_str()));
        config->set_service_ip(m_mysql->Value(2));
    }
    return configList;
}

bool ConfigDao::DeleteConfig(const char *ip, int port)
{
    XCOM_LOG_DEBUG("DeleteConfig");
    std::unique_lock<std::mutex> locker;
    if(!m_mysql)
    {
        XCOM_LOG_DEBUG("m_mysql not init");
        return false;
    }
    if(!ip||port<=0||port>65535||strlen(ip)==0){
        XCOM_LOG_DEBUG("ip or port error");
        return false;
    }
    std::string table_name = CONFIG_TABLE;
    std::stringstream ss;
    ss<<"delete from "<<table_name
       <<" where service_ip='"<<ip<<"'"
       <<" and service_port='"<<port<<"'";
    std::cout<<ss.str()<<std::endl;
    return m_mysql->Query(ss.str());
}

ConfigDao::ConfigDao()
{
}

ConfigDao::~ConfigDao()
{
}
